package com.zhuangjie.shop.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhaungjie.base.conduit.TypeR;
import com.zhaungjie.base.utils.PropertiesCopyUtils.PropertiesCopy;
import com.zhuangjie.mvc.enhance.mp_query_enhance.LambdaQueryWrapperPlus;
import com.zhuangjie.mvc.enhance.mp_query_enhance.LambdaQueryWrapperPlusHelper;
import com.zhuangjie.mvc.enhance.mp_query_enhance.enums.AggregationOperation;
import com.zhuangjie.order.pojo.DishSalesCount;
import com.zhuangjie.security.intercepor.UserRequestInterceptor;
import com.zhuangjie.shop.dto.DishCategorySaveDTO;
import com.zhuangjie.shop.dto.ShopCategoryPageDTO;
import com.zhuangjie.shop.entity.Dish;
import com.zhuangjie.shop.entity.DishCategory;
import com.zhuangjie.shop.entity.DishFlavor;
import com.zhuangjie.shop.entity.ShopDishEvaluate;
import com.zhuangjie.shop.enums.DishCategoryStatus;
import com.zhuangjie.shop.enums.DishStatus;
import com.zhuangjie.shop.feign.OrderFeignService;
import com.zhuangjie.shop.helper.ShopModuleTokenDataProvider;
import com.zhuangjie.shop.mapper.DishCategoryMapper;
import com.zhuangjie.shop.pojo.DishStatisticsInfo;
import com.zhuangjie.shop.service.DishCategoryService;
import com.zhuangjie.shop.service.DishFlavorService;
import com.zhuangjie.shop.service.DishService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品分类 服务实现类
 * </p>
 *
 * @author zhuangjie
 * @since 2023-09-24
 */
@Service
public class DishCategoryServiceImpl extends ServiceImpl<DishCategoryMapper, DishCategory> implements DishCategoryService {

    @Autowired
    private UserRequestInterceptor userRequestInterceptor;

    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
    private DishService dishService;
    @Qualifier("com.zhuangjie.shop.feign.OrderFeignService")
    @Autowired
    private OrderFeignService orderFeignService;

    @Override
    public Page<DishCategory> queryShopCategoryListPage(ShopCategoryPageDTO pageInput, Long shopId) throws Exception {
        if (shopId == null) {
            // 如果没有传入shopId，那就需要手动挂载用户信息（因为接口是公开的，默认不需要挂载用户信息）来获取shopId
            userRequestInterceptor.tryMountCurrentMountLoginState();
            shopId = ShopModuleTokenDataProvider.getShopId();
        }
        if (shopId == null) {
            throw new RuntimeException("无法获取到shopId !");
        }
        String query = pageInput.getKeyword();
        // 组装搜索wrapper
        LambdaQueryWrapper<DishCategory> queryWrapper = new LambdaQueryWrapper();
        if (StringUtils.isNotBlank(query)) {
            query = query.trim();
            queryWrapper.like(DishCategory::getName,query);
        }
        // 只获取登录者对应店铺的分类信息
        queryWrapper.eq(DishCategory::getShopId,shopId);
        // 进行分页参数（currentPage,pageSize）+搜索参数（query）进行分页查询
        Page<DishCategory> page = this.page(new Page<>(pageInput.getCurrentPage(), pageInput.getPageSize()),queryWrapper);
        return page;
    }

    @Override
    public Boolean removeShopDishCategoryById(Long dishCategoryId) {
        // 分类下不能存在菜品，如果存在删除失败
        LambdaQueryWrapper<Dish> queryDishWrapper = Wrappers.lambdaQuery(Dish.class)
                .eq(Dish::getDishCategoryId, dishCategoryId);

        long count = dishService.count(queryDishWrapper);
        if (count > 0) {
            throw new RuntimeException("要删除的分类下存在菜品，删除失败！");
        }
        // 构造删除菜品分类条件
        LambdaQueryWrapper<DishCategory> deleteDishCategoryWrapper = Wrappers.lambdaQuery(DishCategory.class)
                .eq(DishCategory::getId, dishCategoryId)
                .eq(DishCategory::getShopId, ShopModuleTokenDataProvider.getShopId());
        int affectedRowCount = this.baseMapper.delete(deleteDishCategoryWrapper);
        return affectedRowCount > 0;

    }

    @Override
    public DishCategory getShopDishCategoryById(Long dishCategoryId) {
        // 构造查询分类条件
        LambdaQueryWrapper<DishCategory> getDishCategoryWrapper = Wrappers.lambdaQuery(DishCategory.class)
                .eq(DishCategory::getId, dishCategoryId)
                .eq(DishCategory::getShopId, ShopModuleTokenDataProvider.getShopId());
        // 查询
        DishCategory dishCategory = this.baseMapper.selectOne(getDishCategoryWrapper);
        // 如果查询不到应该返回查询错误，而不是成功的响应
        if (dishCategory == null) {
            throw new RuntimeException("店铺不存在该条分类信息！");
        }
        // 查询成功返回
        return dishCategory;

    }

    @Override
    public Boolean saveDishCategory(DishCategorySaveDTO dishCategorySaveDTO) {
        // 新增与更新都只能操作账号关联的店铺下的菜品分类
        DishCategory dishCategory = PropertiesCopy.type(DishCategorySaveDTO.class, DishCategory.class).produce(dishCategorySaveDTO);
        dishCategory.setShopId(ShopModuleTokenDataProvider.getShopId());
        return this.saveOrUpdate(dishCategory);
    }

    @Override
    public List<DishCategory> listShopDishCategory(Long shopId) throws Exception {
        if (shopId == null && (userRequestInterceptor.tryMountCurrentMountLoginState() == null || (shopId = ShopModuleTokenDataProvider.getShopId()) == null)) {
            // 因为接口是开放的，所以想要获取登录者信息，需要手动挂载
            throw new RuntimeException("获取商品分类失败，因为无法获取店铺id！");
        }
        LambdaQueryWrapper<DishCategory> selectShopDishCategoryListWrapper = Wrappers.lambdaQuery(DishCategory.class)
                // 查询指定店铺的菜品分类
                .eq(DishCategory::getShopId, shopId)
                // 查询开启的
                .eq(DishCategory::getStatus, DishCategoryStatus.ENABLE_CONSTANT);

        return this.baseMapper.selectList(selectShopDishCategoryListWrapper);
    }

    @Override
    public List<DishCategory> getShopDishCategory(Long shopId,Boolean isSelectDishFlavor) throws InterruptedException, ExecutionException {
        // 异步查询店铺下的菜品分类
        CompletableFuture<List<DishCategory>> shopDishCategoryCompletableFuture = CompletableFuture.supplyAsync(()->{
            // 查询店铺下的菜品分类
            LambdaQueryWrapper<DishCategory> queryShopDishCategoryWrapper = Wrappers.lambdaQuery(DishCategory.class)
                    .eq(DishCategory::getShopId, shopId);
            return this.list(queryShopDishCategoryWrapper);
        });
        // 异步查询店铺下的菜品
        CompletableFuture<List<Dish>> shopDishCompletableFuture = CompletableFuture.supplyAsync(()->{
            // 查询店铺下的菜品
            LambdaQueryWrapper<Dish> queryShopDishWrapper = Wrappers.lambdaQuery(Dish.class)
                    .eq(Dish::getShopId, shopId)
                    .eq(Dish::getStatus, DishStatus.START_SALE.getValue());
            List<Dish> shopDishList = dishService.list(queryShopDishWrapper);
            if (shopDishList == null || shopDishList.isEmpty()) {
                // 如果没有查到菜品，直接返回了
                return shopDishList;
            }
            // 如果需要查询菜品的口味信息一起返回，需要查询封装到对应的菜品上
            if (isSelectDishFlavor) {
                // 查询上面菜品的口味
                Map<Long, Dish> dishIdAndDishMap = shopDishList.stream().collect(Collectors.toMap(dish -> dish.getId(), dish -> dish));
                LambdaQueryWrapper<DishFlavor> queryDishFlavorWrapper = Wrappers.lambdaQuery(DishFlavor.class)
                        .in(DishFlavor::getDishId, dishIdAndDishMap.keySet());
                List<DishFlavor> dishFlavors = dishFlavorService.list(queryDishFlavorWrapper);
                if (dishFlavors == null || dishFlavors.isEmpty()) {
                    // 上述菜品中都没有口味，直接返回菜品列表
                    return shopDishList;
                }
                // 组装
                dishFlavors.forEach(dishFlavor -> {
                    Dish dish = dishIdAndDishMap.get(dishFlavor.getDishId());
                    if (dish == null) {
                        // 如果该口味没有对应的菜品，跳过
                        return;
                    }
                    List<DishFlavor> currentDishFlavorList = dish.getDishFlavorList();
                    if (currentDishFlavorList == null) dish.setDishFlavorList(currentDishFlavorList = new ArrayList<>());
                    currentDishFlavorList.add(dishFlavor);
                });
            }
            return shopDishList;
        });
        // 店铺近30天的菜品销量（远程调用查询）
        CompletableFuture<List<DishSalesCount>> shopDishSellNumberCompletableFuture = CompletableFuture.supplyAsync(()->{
            try {
                return TypeR.extract(orderFeignService.shopDishSalesCount(shopId, 30));
            } catch (Exception e) {
                throw new RuntimeException("获取店铺近30天的菜品销量失败！");
            }
        });
        // 菜品评价信息
        CompletableFuture<Map<Long, DishStatisticsInfo>> shopDishStatisticsInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            Map<Long, DishStatisticsInfo> shopRateMap = new HashMap<>();
            LambdaQueryWrapperPlusHelper.forGroupUse(
                            new LambdaQueryWrapperPlus<>(ShopDishEvaluate.class)
                                    .eq(ShopDishEvaluate::getShopId, shopId)
                                    .groupBy(ShopDishEvaluate::getDishId)
                            , DishStatisticsInfo.class)
                    .use(AggregationOperation.AVG, ShopDishEvaluate::getSentiment, value -> value.to(DishStatisticsInfo::getGoodRate))
                    .inject(keyMap -> {
                        Long scoreInfoShopId = (Long) keyMap.get(ShopDishEvaluate::getDishId);
                        DishStatisticsInfo dishStatisticsInfo = new DishStatisticsInfo();
                        shopRateMap.put(scoreInfoShopId, dishStatisticsInfo);
                        return dishStatisticsInfo;
                    });
            // 等待获取“店铺近30天的菜品销量”
            try {
                List<DishSalesCount> dishSalesCounts = shopDishSellNumberCompletableFuture.get();
                // 将菜品销量组装到本次异步任务结果集
                for (DishSalesCount dishSalesCount : dishSalesCounts) {
                    // 这里要注意，就算没有`dishSalesCount.getDishId()`的评分信息，要进行new一个来存放销量数量
                    DishStatisticsInfo dishStatisticsInfo = shopRateMap.computeIfAbsent(dishSalesCount.getDishId(), k -> new DishStatisticsInfo());
                    dishStatisticsInfo.setCount(dishSalesCount.getCount());
                }
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage());
            }
            return shopRateMap;
        });


        // 等待所有异步任务完成
        CompletableFuture.allOf(shopDishCategoryCompletableFuture, shopDishCompletableFuture, shopDishStatisticsInfoCompletableFuture).join();
        List<DishCategory> dishCategories = shopDishCategoryCompletableFuture.get();
        List<Dish> dishList = shopDishCompletableFuture.get();
        Map<Long, DishStatisticsInfo> dishScoreInfoMap = shopDishStatisticsInfoCompletableFuture.get();

        if((dishCategories != null && ! dishCategories.isEmpty()) &&
                (dishList != null && ! dishList.isEmpty())) {
            // 获取菜品分类和菜品之间的映射关系
            Map<Long, DishCategory> dishCategoryIdAndCategoryMap = dishCategories.stream().collect(Collectors.toMap(category -> category.getId(), categoty -> categoty));
            // 遍历菜品列表，将菜品放到对应的分类下
            dishList.forEach(dish->{
                DishCategory dishCategory = dishCategoryIdAndCategoryMap.get(dish.getDishCategoryId());
                if (dishCategory == null) return;
                List<Dish> _dishList = dishCategory.getDishList();
                if (_dishList == null) dishCategory.setDishList(_dishList = new ArrayList<>());
                _dishList.add(dish);
            });
            // 将“菜品评价信息”组装到结果集中
            dishList.forEach(dish->dish.setStatisticsInfo(dishScoreInfoMap.get(dish.getId())));

        }
        return dishCategories;
    }

    @Override
    public Map<Long, String> queryDishCategoryNameByIds(List<Long> dishCategoryIdList) {
        LambdaQueryWrapper<DishCategory> queryDishCategoryWrapper = Wrappers.lambdaQuery(DishCategory.class)
                .eq(DishCategory::getShopId, ShopModuleTokenDataProvider.getShopId())
                .in(DishCategory::getId, dishCategoryIdList)
                .select(DishCategory::getId, DishCategory::getName);
        List<DishCategory> list = this.list(queryDishCategoryWrapper);
        if (list == null || list.isEmpty()) {
            throw new RuntimeException("无法查询到指定的菜品分类信息");
        }
        return list.stream().collect(Collectors.toMap(DishCategory::getId, DishCategory::getName));
    }
}
